package cn.kuick.match2.test8;

import java.util.ArrayList;
import java.util.Stack;

public class Calculator {

	public static String normal(String expr) {
		expr = expr.trim();
		expr = expr.replaceAll("\\s", "");
		return expr;
	}
	
	public static boolean isOpe(char ch) {
		return ch == '+' || ch =='-' || ch == '*' || ch=='/';
	}
	
	public static boolean isOpe(String token) {
		if (token.length() > 0) {
			char ch = token.charAt(0);
			return isOpe(ch);
		} 
		
		return false;
	}
	
	public static boolean isLessOrEquealThan(String token1, String token2) {
		if ( (token1.equals("+") || token1.equals("-")) && 
			(token2.equals("*") || token2.equals("/"))) {
			return true;
		}
		
		if ((token1.equals("+") || token1.equals("-")) && 
				(token2.equals("+") || token2.equals("-"))) {
			return true;
		}
		
		if ((token1.equals("*") || token1.equals("/")) && 
				(token2.equals("*") || token2.equals("/"))) {
			return true;
		}
		
		return false;
	}
	
	public static ArrayList<String> spiltTokens(String expr) {
		ArrayList<String> tokens = new ArrayList<String>();
		
		StringBuffer sb = new StringBuffer();
		
		for(int i=0; i<expr.length(); i++) {
			char ch = expr.charAt(i);
			
			if (isOpe(ch)) {
				tokens.add(sb.toString());
				tokens.add("" + ch);
				sb.setLength(0);
			} else {
				sb.append(ch);
			}
		}
		
		tokens.add(sb.toString());
		
		return tokens;
	}
	
	public static ArrayList<String> compile(ArrayList<String> tokens) {
		Stack<String> opes = new Stack<>();
		ArrayList<String> result = new ArrayList<>();
		
		for(int i=0; i<tokens.size(); i++) {
			String token = tokens.get(i);
			
			if (isOpe(token.charAt(0))) {
				while (!opes.isEmpty() && isLessOrEquealThan(token, opes.peek())) {
					result.add(opes.pop());
				}
				
				opes.push(token);
			} else {
				result.add(token);
			}
		}
		
		while (!opes.isEmpty()) {
			result.add(opes.pop());
		}
		
		return result;
	}
	
	public static String basic(String a1, String a2, char ope) {
		long result = 0;
		
		switch(ope) {
			case '+':
				result = Integer.parseInt(a1) + Integer.parseInt(a2);
				break;
			case '-':
				result = Integer.parseInt(a1) - Integer.parseInt(a2);
				break;
			case '*':
				result = Integer.parseInt(a1) * Integer.parseInt(a2);
				break;
			case '/':
				result = Integer.parseInt(a1) / Integer.parseInt(a2);
				break;
		}
		
		return String.valueOf(result);
	}
	
	public static String calculate(ArrayList<String> tokens) {
		Stack<String> stack = new Stack<>();
		
		for(int i=0; i<tokens.size(); i++) {
			String token = tokens.get(i);

			if (isOpe(token)) {
				String a1 = stack.pop();
				String a2 = stack.pop();
				
				String result = basic(a2, a1, token.charAt(0));
				stack.push(result);
			} else {
				stack.push(token);
			}
		}
		
		return stack.pop();
	}
	
	public static String eval(String expr) {
		expr = normal(expr);
		ArrayList<String> tokens = spiltTokens(expr);
		ArrayList<String> ctx = compile(tokens);
		String result = calculate(ctx);
		return result;
	}
	
	public static void main(String[] args) {
		String output = eval("3*2 - 4 / 3");
		System.out.println(output);
	}
}
